/*!	 target.cpp
**	 Target Class Implementation
**
**	Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
**  Copyright (c) 2010 Diego Barrios Romero
**
**	This package is free software; you can redistribute it and/or
**	modify it under the terms of the GNU General Public License as
**	published by the Free Software Foundation; either version 2 of
**	the License, or (at your option) any later version.
**
**	This package is distributed in the hope that it will be useful,
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
**	General Public License for more details.
**
*/

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include "target.h"
#include "string.h"
#include "canvas.h"
#include "target_null.h"
#include "target_null_tile.h"
#include "targetparam.h"

using namespace synfig;
using namespace etl;
using namespace std;

synfig::Target::Book* synfig::Target::book_;
synfig::Target::ExtBook* synfig::Target::ext_book_;

static synfig::Gamma* default_gamma_;

bool
Target::subsys_init()
{
    book_ = new synfig::Target::Book();
    ext_book_ = new synfig::Target::ExtBook();
// TODO:  Do not hard core gamma to 2.2
    default_gamma_ = new synfig::Gamma(1.0 / 2.2);

    // At least one target must be available.
    book()["null"].factory =
        reinterpret_cast<synfig::Target::Factory>(&Target_Null::create);
    book()["null"].filename = "null";
    book()["null"].target_param = TargetParam();
    ext_book()["null"] = "null";

    book()["null-tile"].factory =
        reinterpret_cast<synfig::Target::Factory>(&Target_Null_Tile::create);
    book()["null-tile"].filename = "null-tile";
    book()["null-tile"].target_param = TargetParam();
    ext_book()["null-tile"] = "null-tile";

    return true;
}

bool
Target::subsys_stop()
{
    delete book_;
    delete ext_book_;
    delete default_gamma_;
    return true;
}

Target::Book&
Target::book()
{
    return *book_;
}

Target::ExtBook&
Target::ext_book()
{
    return *ext_book_;
}

Target::Target():
    quality_(4),
    gamma_(*default_gamma_),
    alpha_mode(TARGET_ALPHA_MODE_KEEP),
    avoid_time_sync_(false),
    curr_frame_(0)
{
}

void
synfig::Target::set_canvas(etl::handle<Canvas> c)
{
    canvas = c;
    RendDesc desc = canvas->rend_desc();
    set_rend_desc(&desc);
}

Target::Handle
Target::create(const String &name, const String &filename,
               synfig::TargetParam params)
{
    if (!book().count(name)) {
        return handle<Target>();
    }

    return Target::Handle(book()[name].factory(filename.c_str(), params));
}

int
Target::next_frame(Time& time)
{
    int
    total_frames(1),
                 frame_start(0),
                 frame_end(0);
    Time
    time_start(0),
               time_end(0);

    frame_start = desc.get_frame_start();
    frame_end = desc.get_frame_end();
    time_start = desc.get_time_start();
    time_end = desc.get_time_end();
    // TODO: Add option to exclude last frame
    // If user wants to recover the last buggy behavior then
    // expose this option to the interface using the target params.
    // At the moment it is set to false.
    bool exclude_last_frame(false);
    // Calculate the number of frames
    total_frames = frame_end - frame_start + (exclude_last_frame ? 0 : 1);

    if (total_frames <= 0) {
        total_frames = 1;
    }

    if (total_frames == 1) {
        time = time_start;
    } else {
        time = (time_end - time_start) * curr_frame_ / (total_frames - (exclude_last_frame ? 0 : 1)) + time_start;
    }

    curr_frame_++;


    return total_frames - curr_frame_;
}